package com.xrui.comparison;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.util.*;


public class Comparator {
    static int arraydiffNum = 0;
    /**
     * 返回当前数据类型
     * @param source
     * @return
     */
    public String getTypeValue(Object source){

        if(source instanceof String){
            return "String";
        }

        if(source instanceof Integer){
            return "Integer";
        }

        if(source instanceof Float){
            return "Float";
        }

        if(source instanceof Long){
            return "Long";
        }

        if(source instanceof Double){
            return "Double";
        }

        if(source instanceof Date){
            return "Date";
        }

        if(source instanceof Boolean){
            return "Boolean";
        }

        return "null";
    }


    /**
     * 把Object变成JsonSchema
     * @param source
     * @return
     */
    public Object generateJsonSchema(Object source){

        Object result = new Object();

        //判断是否为JsonObject
        if(source instanceof JSONObject){
            JSONObject jsonResult = new JSONObject();
            JSONObject sourceJSON = (JSONObject)source;
            Set<String> keys = sourceJSON.keySet();
            Iterator<String> iterator = keys.iterator();
            while (iterator.hasNext()){
                String key = (String) iterator.next();
                Object nowValue = sourceJSON.get(key);

                if(nowValue == null || nowValue.toString().equals("null")){
                    jsonResult.put(key,"null");
                }else if(isJsonObject(nowValue)){
                    jsonResult.put(key,generateJsonSchema(nowValue));
                }else if(isJsonArray(nowValue)){
                    JSONArray tempArray = (JSONArray)nowValue;
                    JSONArray newArray = new JSONArray();

                    if(tempArray != null && tempArray.size() > 0 ){
                        for(int i = 0 ;i < tempArray.size(); i++){
                            newArray.add(generateJsonSchema(tempArray.get(i)));
                        }
                        jsonResult.put(key,newArray);
                    }
                }else if(nowValue instanceof List){
                    List<Object> newList = new ArrayList<Object>();

                    for(int i = 0;i<((List) nowValue).size();i++){
                        newList.add(((List) nowValue).get(i));
                    }

                    jsonResult.put(key,newList);
                }else {

                    jsonResult.put(key,getTypeValue(nowValue));
                }

            }
            return jsonResult;
        }


        if(source instanceof JSONArray){
            JSONArray jsonResult = (JSONArray)source;
            JSONArray tempArray = new JSONArray();
            if(jsonResult != null && jsonResult.size() > 0){
                for(int i = 0 ;i < jsonResult.size(); i++){
                    tempArray.add(generateJsonSchema(jsonResult.get(i)));
                }
                return tempArray;
            }

        }

        return getTypeValue(source);

    }



    /**
     * JSON格式比对
     * @param currentJSON
     * @param expectedJSON
     * @return
     */
//    public JSONObject diffJson(JSONObject currentJSON,JSONObject expectedJSON){
//
//        JSONObject jsonDiff = new JSONObject();
//
//
//        Set<String> keys = expectedJSON.keySet();
//        Iterator iterator = keys.iterator();
//        while (iterator.hasNext()){
//            String key = (String)iterator.next();
//            Object expectedValue = expectedJSON.get(key);
//            Object currentValue = currentJSON.get(key);
//            if(currentValue == null){
//                JSONObject tempJSON = new JSONObject();
//                tempJSON.put("category","new");
//                tempJSON.put("value","expectedValue");
//
//                jsonDiff.put(key,tempJSON);
//            }
//            if(!expectedValue.toString().equals(currentValue.toString())){
//                JSONObject tempJSON = new JSONObject();
//                tempJSON.put("value",currentValue);
//                tempJSON.put("expected",expectedValue);
//                jsonDiff.put(key,tempJSON);
//            }
//        }
//        return jsonDiff;
//    }


    /**
     * 判断是否为JSONObject
     * @param value
     * @return
     */
    public boolean isJsonObject(Object value){

        try{
            if(value instanceof JSONObject) {
                return true;
            }else {
                return false;
            }
        }catch (Exception e){
            return false;
        }
    }


    /**
     * 判断是否为JSONArray
     * @param value
     * @return
     */
    public boolean isJsonArray(Object value){

        try{

            if(value instanceof JSONArray){
                return true;
            }else {
                return false;
            }

        }catch (Exception e){
            return false;
        }
    }


    /**
     * JSON格式比对，值不能为空,且key需要存在
     * @param current
     * @param expected
     * @return
     */
    public JSONObject diffFormatJson(Object current,Object expected){

        JSONObject jsonDiff = new JSONObject();

        if(isJsonObject(expected)) {

            JSONObject expectedJSON = (JSONObject)expected;
            JSONObject currentJSON = (JSONObject)current;

            Set<String> expectedkeys = expectedJSON.keySet();
            Set<String> actualkeys = currentJSON.keySet();


            Iterator iterator = expectedkeys.iterator();

            while (iterator.hasNext()) {
                String key = (String) iterator.next();
                Object expectedValue = expectedJSON.get(key);

                if (!currentJSON.containsKey(key)) {
                    JSONObject tempJSON = new JSONObject();
                    tempJSON.put("actualValue", "NewKey");
                    tempJSON.put("expectedValue", expectedValue);
                    jsonDiff.put(key, tempJSON);

                }

                if (currentJSON.containsKey(key)) {
                    Object currentValue = currentJSON.get(key);
                    if ( (expectedValue != null && currentValue == null)
                            || (expectedValue.toString() != "null" && currentValue.toString() == "null")
                    ) {
                        JSONObject tempJSON = new JSONObject();
                        tempJSON.put("actualValue", "null");
                        tempJSON.put("expectedValue", expectedValue);
                        jsonDiff.put(key, tempJSON);
                    }

                    if (expectedValue != null && currentValue != null) {
                        if ((isJsonObject(expectedValue) && !((JSONObject)expectedValue).isEmpty())
                                || isJsonArray(expectedValue) && !((JSONArray)expectedValue).isEmpty()) {
                            JSONObject getResultJSON = null;
                            getResultJSON = diffFormatJson(currentValue, expectedValue);
                            if (getResultJSON != null) {
                                jsonDiff.putAll(getResultJSON);
                            }
                        }else {
                            if (!expectedValue.toString().equals(currentValue.toString())) {
                                JSONObject tempJSON = new JSONObject();
                                tempJSON.put("value", currentValue);
                                tempJSON.put("expected", expectedValue);
                                jsonDiff.put(key, tempJSON);
                            }
                        }
                    }
                }
            }

            if(actualkeys.size() > expectedkeys.size()){
                Set<String> remainingSet = new HashSet<String>();
                remainingSet.addAll(actualkeys);
                remainingSet.removeAll(expectedkeys);
                remainingSet.forEach(key -> {
                            JSONObject tempJSON = new JSONObject();
                            tempJSON.put("actualValue", currentJSON.get(key));
                            tempJSON.put("expectedValue", "empty");
                            tempJSON.put("diffcategory", "newadd");
                            jsonDiff.put(key, tempJSON);

                        }
                );
            }
        }

        if(isJsonArray(expected)){
            JSONArray expectArray = (JSONArray) expected ;
            JSONArray currentArray = (JSONArray) current ;

            if(expectArray.size() != currentArray.size()){
                JSONObject tempJSON = new JSONObject();
                tempJSON.put("actualLenth",currentArray.size());
                tempJSON.put("expectLenth",expectArray.size());
                jsonDiff.put("Length",tempJSON);
            }

            if(expectArray.size() != 0){
                Object expectIndexValue = expectArray.get(0);
                Object currentIndexValue = currentArray.get(0);

                if(expectIndexValue != null && currentIndexValue != null){
                    if ((isJsonObject(expectIndexValue) && !((JSONObject)expectIndexValue).isEmpty() )
                            || (isJsonArray(expectIndexValue) && !((JSONArray)expectIndexValue).isEmpty()) ) {
                        JSONObject getResultJSON = null;
                        getResultJSON = diffFormatJson(currentIndexValue, expectIndexValue);
                        if (getResultJSON != null) {
                            jsonDiff.putAll(getResultJSON);
                        }
                    }
                }
            }

            if(expectArray.size() < currentArray.size()) {
                JSONArray jsonArray = new JSONArray();
                for (int i = expectArray.size() - 1; i < currentArray.size(); i++) {
                    jsonArray.add(currentArray.get(i));
                }
                JSONObject tempJSON = new JSONObject();
                tempJSON.put("actualValue", jsonArray);
                tempJSON.put("expectedValue", "empty");
                tempJSON.put("diffcategory", "newadd");
                jsonDiff.put("arraydiff" +arraydiffNum, tempJSON);
                arraydiffNum++;

            }
        }

        return jsonDiff;
    }
}
